package org.eclipse.kineclipse.handlers;

/**
 * Client.java
 * 
 * Does all the basic I/O routines to connect to the Kinect and parse the events
 * 
 * @author engelman
 * @author daubersc
 * 
 * @version 1.0
 */
import static org.eclipse.kineclipse.handlers.KinectEventsEnum.CLICK;
import static org.eclipse.kineclipse.handlers.KinectEventsEnum.SWIPEDOWN;
import static org.eclipse.kineclipse.handlers.KinectEventsEnum.SWIPELEFT;
import static org.eclipse.kineclipse.handlers.KinectEventsEnum.SWIPERIGHT;
import static org.eclipse.kineclipse.handlers.KinectEventsEnum.SWIPEUP;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;

import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IPerspectiveDescriptor;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;

public class Client {

    private Socket socket;
    private PrintWriter writer;
    private BufferedReader reader;
    private String message = "";
    private Map<String, HashMap<KinectEventsEnum, String>> perspectiveContainer;
    private HashMap<KinectEventsEnum, String> gestureMapperJava, gestureMapperDebug,
	    gestureMapperEMFStore, gestureMapperSVN;
    private String verb = "";
    private String command = "";

    public void openConnection() {

	new Thread(new Runnable() {
	    public void run() {
		try {
		    // Fill our config
		    // TODO: Read from preferences instead of hard coding

		    perspectiveContainer = new HashMap<String, HashMap<KinectEventsEnum, String>>();
		    gestureMapperJava = new HashMap<KinectEventsEnum, String>();
		    gestureMapperDebug = new HashMap<KinectEventsEnum, String>();
		    gestureMapperEMFStore = new HashMap<KinectEventsEnum, String>();
		    gestureMapperSVN = new HashMap<KinectEventsEnum, String>();

		    gestureMapperJava
			    .put(SWIPELEFT,
				    "org.eclipse.jdt.ui.navigate.open.type.in.hierarchy");
		    gestureMapperJava.put(SWIPEUP, "saveall"); // TODO: Add
								 // correct
								 // command
		    gestureMapperDebug.put(SWIPERIGHT,
			    "org.eclipse.debug.ui.commands.StepOver");
		    gestureMapperDebug.put(SWIPELEFT,
			    "org.eclipse.debug.ui.commands.Resume");
		    gestureMapperDebug.put(SWIPEUP,
			    "org.eclipse.debug.ui.commands.StepReturn");
		    gestureMapperDebug.put(SWIPEDOWN,
			    "org.eclipse.debug.ui.commands.StepInto");

		    gestureMapperEMFStore.put(KinectEventsEnum.SWIPERIGHT, "emf.commit"); // TODO:
									   // Add
									   // correct
									   // command
		    gestureMapperEMFStore.put(KinectEventsEnum.SWIPELEFT, "emf.update"); // TODO:
									  // Add
									  // correct
									  // command
		    gestureMapperSVN.put(KinectEventsEnum.SWIPERIGHT, "svn.commit"); // TODO:
								      // Add
								      // correct
								      // command
		    gestureMapperSVN.put(KinectEventsEnum.SWIPELEFT, "svn.update"); // TODO:
								     // Add
								     // correct
								     // command

		    perspectiveContainer.put(
			    "org.eclipse.jdt.ui.JavaPerspective",
			    gestureMapperJava);
		    perspectiveContainer.put(
			    "org.eclipse.debug.ui.DebugPerspective",
			    gestureMapperDebug);
		    perspectiveContainer.put("xxxxjava.emfstore",
			    gestureMapperEMFStore); // TODO: Add correct
						    // perspective ID
		    perspectiveContainer.put("xxxxsvnperspective",
			    gestureMapperSVN); // TODO: Add correct perspective
					       // ID

		    socket = new Socket("127.0.0.1", 12345);
		    writer = new PrintWriter(socket.getOutputStream(),true);

		    // Tests
		    KinectEventsEnum[] subscribtions = {SWIPELEFT, SWIPERIGHT, SWIPEDOWN, SWIPEUP, CLICK};
		    				    
		    reader = new BufferedReader(new InputStreamReader(socket
			    .getInputStream()));
		    subscribe(subscribtions);		    
		    while (true) {
			try {
			    processInput();
			} catch (Exception e) {
			    e.printStackTrace();
			}

		    }
		} catch (UnknownHostException e) {
		    e.printStackTrace();
		} catch (IOException e) {
		    e.printStackTrace();
		}

	    }
	}).start();
    }

    protected void subscribe(KinectEventsEnum[] subscribtions) {
	for (KinectEventsEnum kee : subscribtions) {
	    try {
        	    writer.println("SUBSCRIBE " +  kee.toString()); 
        	    String response = reader.readLine();
        	    if (!response.equalsIgnoreCase("OK")) {
        		System.err.println("Subscribtion failed for " + kee.toString());
        	    }
	    } catch (IOException ioe) {
		    System.err.println("Subscribtion failed for " + kee.toString());
	    }
	}
	
	
    }

    private void processInput() throws IOException {
	message = reader.readLine();
	if (message != null) {
	    System.out.println(message);

	    PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
		public void run() {
		    String perspId = "";
		    IWorkbenchWindow dwindow = PlatformUI.getWorkbench()
			    .getActiveWorkbenchWindow();
		    IWorkbenchPage page = dwindow.getActivePage();
		    if (page != null) {
			IPerspectiveDescriptor desc = page.getPerspective();
			perspId = desc.getId();
		    }
		    System.out.println("In " + perspId + " perspective");

		    // Get verb
		    StringTokenizer st = new StringTokenizer(message, " ");
		    verb = st.nextToken();
		    // TODO: Add more sanity checks (NPE, ...)

		    // Lookup gesture
		    KinectEventsEnum evt = KinectEventsEnum.getEventByName(verb);
		    command = perspectiveContainer.get(perspId).get(evt);
		    if (command!=null) {
		    Display.getDefault().syncExec(new Runnable() {
			public void run() {
			    EclipseActions.runCommand(command);
			    // TODO: Add more alternatives than simply calling
			    // the command (e.g. for commands that take
			    // parameters);
			}
		    });
		    } else {
			System.err.println("Subscribed command " + verb + " not handled in this perspective!");
		    }
		}
	    });
	}

    }

    public void closeConnection() {
	try {
	    writer.close();
	    reader.close();
	    socket.close();
	} catch (IOException e) {
	    e.printStackTrace();
	}

    }

}
